﻿using BoriPeter.FitnessJournal8.Models;
using Caliburn.Micro;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Search;

namespace BoriPeter.FitnessJournal8.ViewModels
{
    public class SearchViewModel : ViewModelBase
    {
        #region MySearchPane
        private SearchPane mySearchPane;
        #endregion

        #region Constructor
        public SearchViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            
        }
        #endregion

        #region OnInitialize()
        protected override async void OnInitialize()
        {
            base.OnInitialize();

            mySearchPane = SearchPane.GetForCurrentView();
            mySearchPane.QuerySubmitted += MySearchPane_QuerySubmitted;
            mySearchPane.SuggestionsRequested += MySearchPane_SuggestionsRequested;

            var categories = FoodCategory.DefaultList;
            FoodCategories = new ObservableCollection<FoodCategory>(categories);
            SelectedFoodCategory = FoodCategories[0];

            var orderBy = FoodOrderBy.DefaultList;
            FoodOrderByTypes = new ObservableCollection<FoodOrderBy>(orderBy);
            SelectedFoodOrderByType = foodOrderByTypes[0];

            var result = await NutritionSource.GetListAsync(SearchExpression);
            SearchResult = new ObservableCollection<Food>(result);
        }
        #endregion

        #region OnGoBack
        protected override void OnGoBack()
        {
            base.OnGoBack();
            mySearchPane.QuerySubmitted -= MySearchPane_QuerySubmitted;
            mySearchPane.SuggestionsRequested -= MySearchPane_SuggestionsRequested;
        }
        #endregion

        #region  OnDeactivate
        protected override void OnDeactivate(bool close)
        {
            base.OnDeactivate(close);

            mySearchPane = SearchPane.GetForCurrentView();
            mySearchPane.QuerySubmitted -= MySearchPane_QuerySubmitted;
            mySearchPane.SuggestionsRequested -= MySearchPane_SuggestionsRequested;
        }
        #endregion

        #region MySearchPane_SuggestionsRequested()
        private async void MySearchPane_SuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args)
        {
            var suggestions = args.Request.SearchSuggestionCollection;
            var query = args.QueryText.ToLower();
            Food food;

            List<string> suggestedWords = new List<string>();
            List<Food> list = await NutritionSource.GetListAsync(
                f => f.Name.ToLower().Contains(query), DAL.FoodService.All);
            if (list != null)
            {
                foreach (var item in list)
                {
                    char[] separator = { ' ', '(', ')', ',', '-' };
                    var words = item.Name.Split(separator);
                    foreach (var word in words)
                    {
                        if (word.ToLower().Contains(query))
                        {
                            if (!(suggestedWords.Contains(word.ToLower())))
                            {
                                suggestedWords.Add(word.ToLower()); 
                            }
                            break;
                        }
                    }
                    if (suggestedWords.Count >= 5) break;
                }
            }

            suggestions.AppendQuerySuggestions(suggestedWords);

            food = await NutritionSource.GetByExpressionAsync(f => f.Name.ToLower().StartsWith(query), DAL.FoodService.All);
            if (food == null)
                food = await NutritionSource.GetByExpressionAsync(f => f.Name.ToLower().Contains(query), DAL.FoodService.All);
            if (food != null)
            {
                suggestions.AppendSearchSeparator("Food Name");
                suggestions.AppendResultSuggestion(
                        food.Name,
                        food.Brand,
                        food.Name,
                        Windows.Storage.Streams.RandomAccessStreamReference.CreateFromUri(
                        new Uri(food.ImageUrl, UriKind.Absolute)),
                        "");
            }

            food = await NutritionSource.GetByExpressionAsync(f => f.Brand.ToLower().StartsWith(query), DAL.FoodService.All);
            if (food == null)
                food = await NutritionSource.GetByExpressionAsync(f => f.Brand.ToLower().Contains(query), DAL.FoodService.All);
            if (food != null)
            {
                suggestions.AppendSearchSeparator("Brand Name");
                suggestions.AppendResultSuggestion(
                        food.Brand,
                        food.Name,
                        "",
                        Windows.Storage.Streams.RandomAccessStreamReference.CreateFromUri(
                        new Uri(food.ImageUrl, UriKind.Absolute)),
                        "");
            }

        }
        #endregion

        #region MySearchPane_QuerySubmitted()
        private async void MySearchPane_QuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args)
        {
            SearchExpression = args.QueryText;
            await LoadSearchResultAsync();
        }
        #endregion

        #region async Task LoadSearchResultAsync()
        private async Task LoadSearchResultAsync()
        {
            List<Food> list;
            if (SelectedFoodCategory.FoodCategoryType == FoodCategoryType.Favorite)
                list = await NutritionSource.GetListAsync(SearchExpression, DAL.FoodService.Favorite);
            else if (SelectedFoodCategory.FoodCategoryType == FoodCategoryType.History)
                list = await NutritionSource.GetListAsync(SearchExpression,DAL.FoodService.History);
            else
                list = await NutritionSource.GetListAsync(SearchExpression);

            if (selectedFoodOrderByType.OrderByType == FoodOrderByType.Brand)
                list = list.OrderBy(f => f.Name).OrderBy(f => f.Brand).ToList();
            else if (selectedFoodOrderByType.OrderByType == FoodOrderByType.Name)
                list = list.OrderBy(f => f.Name).ToList();
            else
                list = list.OrderBy(f => f.Name).OrderBy(f => f.Brand).OrderBy(f => f.LastAccessedDate).ToList();
            SearchResult = new ObservableCollection<Food>(list);

        }
        #endregion

        #region SearchExpression
        private string searchExpression;
        public string SearchExpression
        {
            get { return searchExpression; }
            set { searchExpression = value; }
        }
        #endregion

        #region SearchResult
        private ObservableCollection<Food> searchResult;
        public ObservableCollection<Food> SearchResult
        {
            get
            {
                return this.searchResult;
            }

            set
            {
                this.searchResult = value;
                NotifyOfPropertyChange("SearchResult");
            }
        }
        #endregion

        #region SelectedFood
        private Food selectedFood;
        public Food SelectedFood
        {
            get
            {
                return this.selectedFood;
            }

            set
            {
                this.selectedFood = value;
                Navigate2FoodDetails(value);
            }
        }
        #endregion

        #region FoodCategories
        private ObservableCollection<FoodCategory> foodCategories;
        public ObservableCollection<FoodCategory> FoodCategories
        {
            get
            {
                return this.foodCategories;
            }

            set
            {
                this.foodCategories = value;
                NotifyOfPropertyChange("FoodCategories");
            }
        }
        #endregion

        #region OnSelectionChanged
        public async void OnSelectionChanged()
        {
            await LoadSearchResultAsync();
        }
        #endregion

        #region  SelectedFoodCategory
        private FoodCategory selectedFoodCategory;
        public FoodCategory SelectedFoodCategory
        {
            get
            {
                return this.selectedFoodCategory;
            }

            set
            {
                this.selectedFoodCategory = value;
                NotifyOfPropertyChange("SelectedFoodCategory");
            }
        }
        #endregion

        #region FoodOrderByTypes
        private ObservableCollection<FoodOrderBy> foodOrderByTypes;
        public ObservableCollection<FoodOrderBy> FoodOrderByTypes
        {
            get
            {
                return this.foodOrderByTypes;
            }

            set
            {
                this.foodOrderByTypes = value;
                NotifyOfPropertyChange("FoodOrderByTypes");
            }
        }
        #endregion

        #region SelectedFoodOrderByType
        private FoodOrderBy selectedFoodOrderByType;
        public FoodOrderBy SelectedFoodOrderByType
        {
            get
            {
                return this.selectedFoodOrderByType;
            }

            set
            {
                this.selectedFoodOrderByType = value;
                NotifyOfPropertyChange("SelectedFoodOrderByType");
            }
        }
        #endregion
    }
}
